home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / pty / part02 < prev    next >
Encoding:
Internet Message Format  |  1991-01-08  |  54.4 KB

  1. Path: j.cc.purdue.edu!mentor.cc.purdue.edu!noose.ecn.purdue.edu!samsung!uunet!papaya.bbn.com!rsalz
  2. From: rsalz@bbn.com (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v23i032:  Run a program under a pty session, Part02/06
  5. Message-ID: <2882@litchi.bbn.com>
  6. Date: 10 Oct 90 14:16:28 GMT
  7. Organization: BBN Systems and Technologies, Cambridge MA
  8. Lines: 1689
  9. Approved: rsalz@uunet.UU.NET
  10. X-Checksum-Snefru: 6fe1a084 64d83c14 ac39c37e bf52d9f3
  11.  
  12. Submitted-by: Dan Bernstein <brnstnd@kramden.acf.nyu.edu>
  13. Posting-number: Volume 23, Issue 32
  14. Archive-name: pty/part02
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then feed it
  18. # into a shell via "sh file" or similar.  To overwrite existing files,
  19. # type "sh file -c".
  20. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  21. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  22. # Contents:  INSTALLREADABLE master.c pty.c
  23. # Wrapped by rsalz@litchi.bbn.com on Wed Oct 10 10:11:37 1990
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 2 (of 6)."'
  27. if test -f 'INSTALLREADABLE' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'INSTALLREADABLE'\"
  29. else
  30.   echo shar: Extracting \"'INSTALLREADABLE'\" \(22621 characters\)
  31.   sed "s/^X//" >'INSTALLREADABLE' <<'END_OF_FILE'
  32. XThis is a typescript of INSTALL on a Sun 4 running SunOS 4.0.3.
  33. XI've inserted some further comments at spots where INSTALL might give
  34. Xdifferent results on different machines.
  35. X
  36. X
  37. X
  38. XHi, and welcome to the pty install script.
  39. Xpty is a program for managing pseudo-terminals.
  40. X
  41. XI'm not actually going to install anything.
  42. XI'll just guide you through what has to be done,
  43. Xfrom compiling through installation.
  44. X
  45. XOne advantage of this hands-off philosophy is that
  46. Xyou can kill and restart this script at any time.
  47. XYou may prefer to read through INSTALLREADABLE,
  48. Xwhich has the same information.
  49. X
  50. XIn the first part of this script, I'll lead you through configuration.
  51. XFor the moment, don't actually change anything in your system. Just
  52. Xalternate between reading this script and fooling around with the
  53. XMakefile, and I'll remind you later, after compilation, of what has
  54. Xto be changed elsewhere.
  55. X
  56. XI need the following programs: echo, tr [-d], man, sed [-n], grep, test.
  57. X
  58. X----- Press return to continue. 
  59. X
  60. XThe first versions of pty were designed on a BSD 4.2-based system.
  61. XDuring May 1990 pty 3.0 was written completely from scratch,
  62. Xon a BSD 4.3-based system. It has been thoroughly tested on
  63. Xseveral BSD 4.3-based systems, tested with a few Makefile changes
  64. Xon several BSD 4.2-based systems, and run on at least one mutant.
  65. X
  66. XIf you make it through installation and testing and get pty running,
  67. Xplease send a note to the author, Dan Bernstein, on the Internet
  68. Xat brnstnd@nyu.edu. Let him know your computer model, OS version, and
  69. Xwhat changes you had to make. If you have any trouble, please also get
  70. Xin touch with the author. If you have a different kind of system with
  71. Xpseudo-terminal support that could use a pty port, the author would
  72. Xlove to hear about it.
  73. X
  74. XOne note: Like all software, pty comes without warranty, to the extent
  75. Xpermitted by applicable law. Use it at your own risk.
  76. X
  77. X----- Press return to continue. 
  78. X
  79. XI assume that you don't want to make any major changes
  80. Xto your computer just to take advantage of pty's capabilities.
  81. XYou might not even have a privileged account, for all I know.
  82. X
  83. XThe first major decision you have to make is what privileges to give pty.
  84. XObviously if you don't have privileges then pty won't either;
  85. Xthis is Case UN.
  86. X
  87. X----- Press return to continue. 
  88. X
  89. XThere are several good reasons for giving programs privileges.
  90. XMost importantly, privileged programs can precisely control access
  91. Xto a shared resource. pty supports an interactive user list in
  92. X/etc/utmp, a login-logout record in /usr/adm/wtmp, and controlled
  93. Xaccess to the pseudo-terminal files themselves, including security and
  94. Xmode changing. None of these are possible if pty isn't setuid.
  95. X
  96. XIf your system has a lot more tty security than usual, you probably
  97. Xwon't be able to run pty without privileges. (However, if your system
  98. Xhas a lot more tty security than usual, it's almost certainly running
  99. Xpty anyway.)
  100. X
  101. X----- Press return to continue. 
  102. X
  103. XIf you do want pty to have privileges, you have to decide between
  104. Xsetting up pty as root (Case ROOT) or as some other user, say ``pty''
  105. X(Case PTY). Staying away from root has the advantage that problems
  106. Xcan't possibly destroy all security in one blow. However, root has
  107. Xseveral advantages, mainly because of BSD limitations: 1. A process
  108. Xcan't change ownership of a file between its euid and uid. Only root
  109. Xcan change ownership. It shouldn't be necessary to change ownership
  110. Xof ptys anyway, but that's what many programs assume. 2. MAXUPRC in
  111. X<sys/param.h> limits the number of processes under a given *effective*
  112. Xuid. This absolutely idiotic behavior is a serious problem for programs
  113. Xsetuid to anything other than root. pty tries to work around this
  114. Xproblem, but there are no true solutions. 3. Despite the documentation
  115. Xin kill(2), many machines don't allow non-root processes to send
  116. XCONT to children with a different uid. Unlike almost all other programs,
  117. Xpty sensibly handles its child stopping and restarting; but this won't
  118. Xwork on those machines if pty isn't root.
  119. X
  120. XYou should decide now between Case ROOT and Case PTY.
  121. X
  122. X----- Press return to continue. 
  123. X
  124. XWhether you've decided on ROOT, PTY, or UN,
  125. Xnow is the time to check the security of the entire pty package.
  126. XIt'd be difficult for anything to slip through the checks by the
  127. Xauthor, testers, and source group moderator, but you should take
  128. Xat least a moment to look for your pet security peeves.
  129. X
  130. XA couple of security notes: The only open(,O_CREAT) in pty is in
  131. Xmaster.c, at the top of master(), of a file with a very restricted
  132. Xform constructed from the filename of a /dev/ttyxx. There are no
  133. Xcreat()s. The only bind() is in sock.c's pty_readsock(), which is
  134. Xcalled only from master.c's master() to create a socket with a
  135. Xsimilarly restricted name. (fnsty is changed in sigler but not in
  136. Xmaster.) The only exec() is in slave.c, after a forced setreuid()
  137. Xto a uid that is only set to getuid(). unlink(), mkdir(), and rename()
  138. Xare only used with restricted pathnames.
  139. X
  140. X----- Press return to continue. 
  141. X
  142. XIn Case PTY, you have to set up a new uid, say ``pty'' (or whatever
  143. Xusername you want). pty should not allow logins. Its password should
  144. Xbe an asterisk; its home directory should be /nonexistent; its shell
  145. Xshould be /bin/true. In other words, the only access to user pty
  146. Xshould be through these setuid programs.
  147. X
  148. XIn any privileged case you should have group tty,
  149. Xwhich most BSD 4.3 systems have as gid 4. 
  150. X
  151. XRunning $ ttygroup="`sed -n 's/^tty:[^:]*:\(.*\):.*/\1/p' < /etc/group`" ...
  152. X
  153. XI see that you have a tty group, 4 as usual. Good.
  154. X
  155. X[Note: Under SunOS 4.0.3, ttygroup comes out to 4. On systems where it
  156. Xcomes out to nothing at all, you have to add the line tty:4:*:root to
  157. X/etc/group. On systems where the tty group is something other than 4,
  158. Xjust remember it.]
  159. X
  160. X----- Press return to continue. 
  161. X
  162. XNext, we're going to drudge through the config.h file.
  163. X
  164. XIn Cases ROOT or PTY, you have to set up a system-wide directory
  165. Xfor storing information about pty sessions. (A session is a program
  166. Xstuck under a pty that you can disconnect and reconnect.) Users can
  167. Xget around this directory, storing the information in ~/.pty and
  168. Xrevoking any privileges, with pty -xS; you can even make this default
  169. Xby setting flagxsetuid = 0 in globals.c. However, a single system-wide
  170. Xdirectory is safer.
  171. X
  172. XAnyway, that directory, PTYDIR, should be mode 0700, owner root in case
  173. XROOT or pty in case PTY, group irrelevant. PTYDIR is defined in config.h
  174. Xas /usr/etc/pty by default; if you choose a different directory, add
  175. X-DPTYDIR=\"/what/ever/dir/ect/ory\" to CCOPTS in the Makefile.
  176. X
  177. XIn Case UN, you may want to set up a directory ~/PTY inside your home
  178. Xdirectory, and set PTYDIR to that; you may want to set flagxsetuid = 0
  179. Xin globals.c; or you may want to just type -xS to pty all the time. I
  180. Xrecommend the first strategy.
  181. X
  182. X----- Press return to continue. 
  183. X
  184. XNext come pseudo-terminal pathnames. I assume that your ptys are
  185. Xlabelled as /dev/ptyxx and /dev/ttyxx, where xx is any two-letter
  186. Xextension. pty can support any initial strings instead of these,
  187. Xbut some of the utilities have /dev/tty hardcoded, and lots of other
  188. Xprograms running around assume those names. If you're desperate,
  189. Xdefine DEVMTY and DEVSTY in the Makefile, and figure out what has to
  190. Xbe changed in util/*. (Sorry.)
  191. X
  192. X----- Press return to continue. 
  193. X
  194. XThe extension is traditionally [p-za-o][0-9a-f]. The first letter of the
  195. Xsecond string is special: if /dev/ttyq0 doesn't exist, for example, then
  196. Xnone of /dev/ttyq[0-9a-f] will be used. (That's called a pty bank.)
  197. X
  198. XYou can change those strings by defining, e.g., PTY1=\"ABCDEFG\" or
  199. XPTY2=\"02468abfq\" in the Makefile. You have at least four choices here:
  200. X1. Give pty its own, new, banks of new pseudo-terminals with weird bank
  201. Xnames not including a through z, and define PTY1 appropriately. pty will
  202. Xonly use those new ptys, and older programs will just use the old ptys.
  203. XThis may require reconfiguring your system for the larger number of
  204. Xterminals. 2. Give pty some new banks, and take out some old ones to
  205. Xmake up for it. 3. Give pty a chunk of the old banks. 4. Give pty all
  206. Xthe old banks.
  207. X
  208. XNote that pty searches randomly through PTY1 and PTY2 by default; for
  209. Xefficiency, PTY1 really should reflect exactly the pty banks you have.
  210. X
  211. X----- Press return to continue. 
  212. X
  213. XSo now you've decided on new ptys, or set aside some or all of your
  214. Xold ptys, and changed PTY1 and PTY2 appropriately. Because BSD gives a
  215. Xprocess very little control over its controlling terminal, pty has to
  216. Xpass a terminal name explicitly when it reconnects. If any of your tty
  217. X(not just pseudo-tty!) filenames are longer than 30 characters, you have
  218. Xto set -DTTYNAMELEN=60 (or whatever) in the Makefile.
  219. X
  220. X----- Press return to continue. 
  221. X
  222. X/etc/utmp has traditionally listed all users logged on.
  223. XThis nebulous concept has evolved through the years; given the way
  224. Xthat most programs use utmp, utmp is probably better defined as a
  225. Xlist of all interactive sessions. Anyway, pty supports this file,
  226. Xand will make an entry in it when given -xu. If you have a different
  227. Xfile, add -DPTYUTMP_FILE=\"/foo/bar/utmp\" to DEFINES in the Makefile.
  228. X
  229. XNote that /etc/utmp is unprotected (mode 666) on Suns. This was Sun's
  230. Xattempt to let unprivileged programs manage the file. Unforunately, this
  231. Xerror in judgment opens up a huge security hole, which even on
  232. Xsingle-user machines is an invitation to make mistakes. I advise you to
  233. Xmake /etc/utmp owned by root in Case ROOT or pty in Case PTY, mode 644.
  234. XThere aren't many unprivileged programs that don't understand the
  235. Xpty interface; people on non-Suns have survived so far, and there's
  236. Xno reason for you to keep subscribing to an insecure model of resource
  237. Xsharing.
  238. X
  239. X----- Press return to continue. 
  240. X
  241. XAlthough pty will put an entry into utmp, it doesn't really support
  242. Xthe remote-host field. There is no logical association between sessions
  243. Xand connections; why should a login require a pty, and why should a
  244. Xsession only stick around for one connection? So pty just puts "pty" in
  245. Xthe host field. You can change this with -DPTYUTMP_HOST=\"foo\"; you may
  246. Xeven want to make PTY_UTMPHOST call a function that you define.
  247. X
  248. X(Similar comments apply to PTYWTMP_HOST. There are also PTYUTMP_SWHOST
  249. Xand PTYWTMP_SWHOST, defaults PTYUTMP_HOST and "pty-sessuser"
  250. Xrespectively; see util/sessuser.1 for more information.)
  251. X
  252. X----- Press return to continue. 
  253. X
  254. X/usr/adm/wtmp has traditionally recorded all logins, logouts, reboots,
  255. Xftp sessions, and various other interesting events. (The entry for a
  256. Xline in utmp is the last entry for that line in wtmp.) pty supports wtmp
  257. Xfully, in the same way as utmp. You should make wtmp mode 644, owner
  258. Xroot or pty as appropriate. Change PTYWTMP_FILE if /usr/adm/wtmp is
  259. Xsomewhere else.
  260. X
  261. X----- Press return to continue. 
  262. X
  263. XYou can turn off utmp support by uncommenting the NO_UTMP line in
  264. Xconfig.h. (Just delete the initial /*.) You can also turn off support
  265. Xfor wtmp, disconnectable sessions, or changing pseudo-terminal file
  266. Xownership; just uncomment the appropriate line. You can force use of
  267. Xeach of these features by defining MUST_UTMP, etc., in the same way.
  268. X
  269. XNote that the usual login programs do their own wtmp management, and
  270. Xmany accounting programs incorrectly equate session time with connect
  271. Xtime, so users will rarely want wtmp. As more programs appear using the
  272. Xpty interface, and as login programs start using a more logical system
  273. Xfor accounting, MUST_WTMP may become an appropriate way to monitor
  274. Xpseudo-terminal usage. For the moment, I do not advise setting any NO
  275. Xor MUST.
  276. X
  277. X----- Press return to continue. 
  278. X
  279. Xpty subscribes (not very willingly) to the BSD 4.3 model of pty
  280. Xprotection, with a few twists. All ptys are under group tty, at all
  281. Xtimes; if you don't have a tty group, all ptys should be under some
  282. Xother protected group at all times. Anyway, pty will change the group of
  283. Xeach pseudo-terminal file to PTYGROUP, default 4, under -xc.
  284. X
  285. X
  286. XSince you already have a tty group, gid 4, you're fine.
  287. X
  288. X[Note: If your tty group is something other than 4, add -DPTYGROUP=6 (or
  289. Xwhatever) to the Makefile.]
  290. X
  291. X
  292. X(Under Case UN, don't worry about all this group stuff. Just leave
  293. XPTYGROUP alone.)
  294. X
  295. X----- Press return to continue. 
  296. X
  297. XUnder -xc, pty changes the pseudo-terminal owner to the current real
  298. Xuid. The fact that terminals need to be in the file hierarchy reflects a
  299. Xserious failure in the BSD terminal model; but anyway, many programs
  300. Xexpect to be able to fool around with /dev/tty. After pty is done with
  301. Xthe terminal, it sets the owner back to its effective uid. You can
  302. Xmodify this behavior by changing PTYOWNER from euid to something else.
  303. X
  304. XUnder Case UN, PTYOWNER is irrelevant.
  305. X
  306. X----- Press return to continue. 
  307. X
  308. XWhile a tty is unused, BSD systems traditionally leave it unprotected.
  309. XUnfortunately, this leaves some huge security holes. Here's one of
  310. Xthe biggest advantages of a privileged pty manager: unused ttys don't
  311. Xhave to be left open for any random program to use. After it's done
  312. Xwith a pseudo-terminal, pty changes it to mode UNUSEDPTYMODE, default
  313. X0600. (This is another case of a poor model for kludging pty support
  314. Xinto unprivileged programs. If you haven't set up separate pty banks
  315. Xfor pty, and you really want to allow unprivileged access to unused
  316. Xptys, try mode 0660 and make those other programs setgid to tty.)
  317. X
  318. XA tty that someone's using can be in many different modes. Typically
  319. XUSEDPTYMODE should be 0600, which means user-only access, messages off,
  320. Xbiff off. If you really, really, really want to make the mistake of
  321. Xhaving messages or biff on by default, try 0620, 0700, or 0720. Note
  322. Xthat the world protection should always be 0: the point of the tty group
  323. Xis that only setgid-tty programs can access ttys.
  324. X
  325. XAs usual, you can't do anything about these in Case UN.
  326. X
  327. X----- Press return to continue. 
  328. X
  329. XNow we're past generic configuration and down to your system's
  330. Xnitty-gritty.
  331. X
  332. XFor purity, pty has SIGRET_TYPE, default int, as the type returned by a
  333. Xsignal handler. On Suns and ANSI-compliant machines, you should define
  334. XSIGRET_TYPE=void. Then you can admire the lint -haxc *.c output.
  335. X
  336. X----- Press return to continue. 
  337. X
  338. XOUTBUFSIZE, default 16384, is the size of the buffer pty keeps between
  339. Xthe incoming data and the pseudo-tty, and between the pseudo-tty and the
  340. Xoutgoing data. If you want to spare less than 32K per pty just for
  341. Xbuffer space, feel free to change this.
  342. X
  343. X----- Press return to continue. 
  344. X
  345. XGENERIC is another concession to ANSI taste. GENERIC * should be a
  346. Xpointer type that any other pointer can be safely converted to and back;
  347. XGENERIC is char by default, but on newer machines can be set to void.
  348. XAs it'll be at least five years before ANSI manages to outlaw char *,
  349. Xand as void * is often invalid, I advise you to leave GENERIC alone.
  350. X
  351. X----- Press return to continue. 
  352. X
  353. Xpty attempts to forward window-size changes transparently. It also
  354. Xsupports the auxiliary characters structure, which lets you type a
  355. Xsingle character to get system and tty status.
  356. X
  357. XRunning $ man 4 tty | sed 's///g' | grep -s winsize
  358. XReformatting page.  Wait... done
  359. X
  360. XI see you don't have window sizes.
  361. XYou'll have to comment out #define TTY_WINSIZE in config.h.
  362. X(This may be inaccurate on Suns; try grep winsize /usr/include/sys/tt*.h.)
  363. X
  364. X[Note: As a matter of fact, the test is inaccurate under SunOS 4.0.3,
  365. Xwhich does have window sizes. If you have window sizes, you don't have
  366. Xto do anything.]
  367. X
  368. XRunning $ man 4 tty | sed 's///g' | grep -s auxchars
  369. XReformatting page.  Wait... done
  370. X
  371. XI see you don't have auxiliary characters.
  372. X
  373. X[Note: This is the usual. If you have auxiliary characters and want pty
  374. Xto understand them, uncomment #define TTY_AUXCHARS in config.h.]
  375. X
  376. X----- Press return to continue. 
  377. X
  378. Xpty also puts siginterrupt() and usleep() to good use in working
  379. Xaround BSD limitations. Without siginterrupt(), there is absolutely
  380. Xno way to get per-process non-blocking I/O, so pty may block when it
  381. Xdoesn't have to (namely, when it has N bytes to write to the output,
  382. Xthe output is a pipe with M bytes of space, and N > M > 0). If you
  383. Xdefine SIGINTERRUPT (as default), pty will take some extra effort to
  384. Xnever, ever, ever block when it doesn't have to.
  385. X
  386. XAt one point, pty pauses to kludge around a common bug in UNIX-domain
  387. Xsockets. With usleep() it will pause much more briefly. This makes
  388. Xreconnects much faster.
  389. X
  390. XRunning $ man siginterrupt | sed 's///g' | grep -s siginterrupt
  391. XReformatting page.  Wait... done
  392. X
  393. XI see you have siginterrupt(). Good.
  394. X
  395. XWeird, are you BSD 4.3?
  396. X
  397. X[Note: Without siginterrupt(), you have to comment out #define
  398. XSIGINTERRUPT in config.h.]
  399. X
  400. XRunning $ man usleep | sed 's///g' | grep -s usleep
  401. XReformatting page.  Wait... done
  402. X
  403. XI see you have usleep(). Good.
  404. X
  405. X[Note: Without usleep(), you have to comment out #define USLEEP in
  406. Xconfig.h.]
  407. X
  408. X----- Press return to continue. 
  409. X
  410. XFinally (almost done with configuration!), we have to make sure that you
  411. Xhave UNIX-domain sockets, and check whether you have file descriptor
  412. Xpassing.
  413. X
  414. XRunning $ test -r /usr/include/sys/un.h
  415. X
  416. XI see you have UNIX-domain sockets. Good.
  417. X
  418. X[Note: If <sys/un.h> isn't there, you probably don't have UNIX-domain
  419. Xsockets, which means you can't have disconnectable sessions. Define
  420. XNO_UNIXSOCKS in config.h.]
  421. X
  422. XRunning $ man recvmsg | sed 's///g' | grep -s rights
  423. XReformatting page.  Wait... done
  424. X
  425. XI see you have file descriptor passing. Good. (Your fd passing may be
  426. Xbuggy, as it's a relatively new, powerful, and rarely exploited
  427. Xfeature. If you have trouble, try defining NO_FDPASSING.)
  428. X
  429. X[Note: If there isn't a recvmsg() man page mentioning access rights, you
  430. Xprobably don't have file descriptor passing. This isn't a disaster,
  431. Xthough it means that reconnected sessions will be as slow as they are in
  432. Xprograms other than pty. Define NO_FDPASSING.]
  433. X
  434. X----- Press return to continue. 
  435. X
  436. XWhew! We've finally made it through configuration. If you want, try
  437. Xrunning lint -haxc *.c or whatever your favorite code checker is; the
  438. Xlint here gives some bogus errors about correct char * casts, an error
  439. Xbecause the SIG_IGN definition is unportable, and a couple of bzero
  440. Xcomplaints because FD_ZERO isn't defined very well.
  441. X
  442. XIf you're on an old system without FD_ZERO, FD_SET, and FD_ISSET in
  443. X<sys/types.h>, I recommend you upgrade. Try copying file.h.old to file.h
  444. X(the original version is in file.h.new).
  445. X
  446. XWe're nearly at the end. Change CC and CCOPTS in the Makefile for any
  447. Xlast-minute additions; if you're worried, change -s to -g for debugging.
  448. XNow compile! % (date; make) >>& Makelog & and come back to this script.
  449. X
  450. X----- Press return to continue. 
  451. X
  452. XWhile the program is compiling, let's start providing some support.
  453. X(If the compile finishes or has an error, just ignore it for the
  454. Xmoment.) These are some real changes, so watch out!
  455. X
  456. XFirst---in Case PTY only!---make a new uid, pty, not allowing logins.
  457. X
  458. X/etc/passwd:  pty:*:whatever:4:::/bin/true
  459. X
  460. X----- Press return to continue. 
  461. X
  462. XSecond, make sure you have a tty group set up.
  463. X
  464. X/etc/group:  tty:*:4:root
  465. X
  466. X----- Press return to continue. 
  467. X
  468. XThird, make PTYDIR.
  469. X
  470. XROOT: # mkdir /usr/etc/pty; chmod 700 /usr/etc/pty
  471. XPTY: # mkdir /usr/etc/pty; chown pty /usr/etc/pty; chmod 700 /usr/etc/pty
  472. XUN: % mkdir ~/PTY; chmod 700 ~/PTY
  473. X
  474. X----- Press return to continue. 
  475. X
  476. XFourth, make sure you have all the pseudo-terminal files set up and
  477. Xappropriately configured.
  478. X
  479. XChange each of them to group tty.
  480. X
  481. XChange each of them to owner pty in case PTY or root in case ROOT.
  482. X
  483. XChange each of them to mode UNUSEDPTYMODE (0600).
  484. X
  485. X----- Press return to continue. 
  486. X
  487. XFifth, make sure /etc/utmp and /usr/adm/wtmp exist, owned by root in
  488. XCase ROOT or pty in Case PTY, each mode 644. (In Case UN, you probably
  489. Xwant to be working on a Sun with its insecure /etc/utmp, so that pty can
  490. Xtake advantage of it. Sigh.)
  491. X
  492. X----- Press return to continue. 
  493. X
  494. XSixth, I advise that you make a special directory /usr/local/ptybin for
  495. Xpty and its associated utilities, with symbolic links in /usr/local.
  496. XThis choice isn't too important, but it's easier if you know a
  497. Xplace to put programs.
  498. X
  499. X----- Press return to continue. 
  500. X
  501. XOkay. You've done about all that can be done before compilation
  502. Xfinishes, so go do something else.
  503. X
  504. X----- Press return to continue. 
  505. X
  506. XThe compile should be done now. If all went well, the make should have
  507. Xexited normally, Makelog should show no errors, and you should have an
  508. Xexecutable pty program sitting in this directory. Unfortunately, life
  509. Xisn't always so generous. Here are a few of the more common errors.
  510. X
  511. XThe loader complains about missing getopt(), optarg, and optind: These
  512. Xare all in the getopt library, available in the early volumes of
  513. Xcomp.sources.unix. If you use GNU getopt, please make sure you
  514. Xunderstand the implications of its license.
  515. X
  516. XThe loader complains about missing FD_ZERO, FD_SET, and FD_ISSET: Try
  517. Xcopying file.h.old to file.h and recompiling. If the compiler gives
  518. Xvarious further errors related to these macros, uncomment the
  519. Xcommented-out lines in file.h.old, copy to file.h, and try once again.
  520. X
  521. Xbcopy() isn't defined: In pty.h, change bcopy(src,dst,num) to
  522. Xmemcpy(dst,src,num). (Note the order.) Try again.
  523. X
  524. XIf you still can't get the code to compile, let the author know.
  525. X
  526. X----- Press return to continue. 
  527. X
  528. XNext, compile the utilities. There isn't much to say about them;
  529. Xthey're all public domain, some of them clones of or improvements
  530. Xover standard utilities, some of them clones with special features to
  531. Xwork with pty, some of them entirely new programs for pty's new
  532. Xfeatures. Just glance at the top of util/Makefile; then
  533. X% cd util; (date; make) >>& Makelog & and wait.
  534. X
  535. XWarning: The pty session directory is hardcoded in util/sessutil.c.
  536. XIf you have changed PTYDIR, check through sessutil.c carefully.
  537. X
  538. X----- Press return to continue. 
  539. X
  540. XSo now you should have some executables sitting around collecting dust.
  541. XIn Cases ROOT and PTY, put {pty,biff,disconnect,mesg,reconnect,sesskill,
  542. Xsesslist,sessname,sessuser} into a system-wide directory, owner root or
  543. Xpty, mode 4755. Put wall and write into the same place, group tty, mode
  544. X2755. Put {condom,excloff,exclon,last,lock,script,script.tidy,sess,tiocsti,
  545. Xtty,u,who,xdisconnect,xreconnect,xsesskill,xsesslist,xsessname,xsessuser}
  546. Xinto the same place, mode 755. Make absolutely sure none of the shell
  547. Xscripts are setuid.
  548. X
  549. XIn Case UN, just put all the programs somewhere in your PATH.
  550. X
  551. XThat's it! Try running TESTS now.
  552. X
  553. X(Two other things you have to do at some point: move your old script,
  554. Xbiff, mesg, and so on to script.old, biff.old, mesg.old, etc., with
  555. Xsymbolic links to the new versions in their place; and move the old
  556. X/usr/man/{script,biff,mesg,...}.1 somewhere else, copy all the *.1
  557. Xhere to /usr/man/man1, and run /etc/catman.)
  558. END_OF_FILE
  559.   if test 22621 -ne `wc -c <'INSTALLREADABLE'`; then
  560.     echo shar: \"'INSTALLREADABLE'\" unpacked with wrong size!
  561.   fi
  562.   # end of 'INSTALLREADABLE'
  563. fi
  564. if test -f 'master.c' -a "${1}" != "-c" ; then 
  565.   echo shar: Will not clobber existing file \"'master.c'\"
  566. else
  567.   echo shar: Extracting \"'master.c'\" \(18086 characters\)
  568.   sed "s/^X//" >'master.c' <<'END_OF_FILE'
  569. X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */
  570. X
  571. X#include <sys/types.h>
  572. X#include <sys/time.h>
  573. X#include <sys/resource.h>
  574. X#include <sys/wait.h>
  575. X#include <stdio.h>
  576. X#include "err.h"
  577. X#include "config.h"
  578. X#include "pty.h"
  579. X#include "master.h"
  580. X#include "sig.h"
  581. X#include "tty.h"
  582. X#include "file.h"
  583. X#include "sock.h"
  584. X#include "logs.h"
  585. X#include "misc.h"
  586. X
  587. Xstatic char fnre[20];
  588. X
  589. Xstatic char fnsess[20];
  590. Xstatic int fdsess;
  591. X
  592. Xstatic char *glfnsty;
  593. X
  594. Xstatic char soutbuf[OUTBUFSIZE];
  595. Xstatic char sptybuf[OUTBUFSIZE];
  596. X
  597. Xstatic struct ttymodes tmowinpty;
  598. Xstatic struct ttymodes tmowintty;
  599. X
  600. Xstatic char *outbuf = soutbuf;
  601. Xstatic int outbufsiz = OUTBUFSIZE;
  602. Xstatic int outbuflen = 0;
  603. Xstatic char *ptybuf = sptybuf;
  604. Xstatic int ptybufsiz = OUTBUFSIZE;
  605. Xstatic int ptybuflen = 0;
  606. X
  607. Xstatic int flagconnected = 1; /* 0: disconnected. 2: idling for stop. */
  608. X                              /* 3: idling for stop but child is dead. */
  609. Xstatic int flagchild = 1; /* 0: dead. 2: stopped. */
  610. Xstatic int childsig; /* signal that stopped/killed child */
  611. Xstatic int flagsigler = 1; /* 0: dead. */
  612. Xstatic int siglerpid; /* only defined if flagconnected */
  613. Xstatic int slavepid;
  614. X
  615. Xstatic int flagqwinch = 0;
  616. X
  617. Xstatic void quickdeath(i)
  618. Xint i;
  619. X{
  620. X /* All exits from master() go through here. */
  621. X if (flagsession) (void) unlink(fnsess);
  622. X if (flagxchown)
  623. X   (void) fchown(fdsty,PTYOWNER,PTYGROUP);
  624. X (void) fchmod(fdsty,UNUSEDPTYMODE);
  625. X date = now();
  626. X if (flagxutmp)
  627. X   if (utmp(glfnsty + PTYUTMP_OFFSET,"","",date) == -1)
  628. X     ; /* too bad. */
  629. X if (flagxwtmp)
  630. X   if (wtmp(glfnsty + PTYWTMP_OFFSET,"","",date) == -1)
  631. X     ; /* too bad. */
  632. X fatal(i);
  633. X}
  634. X
  635. Xstatic void death(i)
  636. Xint i;
  637. X{
  638. X (void) kill(siglerpid,SIGTERM);
  639. X /* XXX: should wait while flagsigler */
  640. X quickdeath(i);
  641. X}
  642. X
  643. X/*ARGSUSED*/
  644. Xstatic void sig_force(i)
  645. Xsig_num i;
  646. X{
  647. X /* Forced death, presumably from the sesskill program. */
  648. X sig_ignore(SIGCHLD);
  649. X /* XXX: Should we test for !flagchild here? sesskill does. */
  650. X flagchild = 0;
  651. X quickdeath(SIGCHLD);
  652. X}
  653. X
  654. X/*ARGSUSED*/
  655. Xstatic void sig_usr2(i)
  656. Xsig_num i;
  657. X{
  658. X if (flagsession)
  659. X  {
  660. X   int newuid = uid;
  661. X   char newsuid[10];
  662. X   char foo[100];
  663. X
  664. X   /* XXX: We should have some error recovery here! */
  665. X
  666. X   (void) lseek(fdsess,(long) 0,0);
  667. X   (void) read(fdsess,(char *) &newuid,sizeof(int));
  668. X   (void) sprintf(newsuid,"%d",newuid);
  669. X
  670. X   (void) chdir("..");
  671. X   if (chdir(newsuid) == -1)
  672. X    {
  673. X     (void) mkdir(newsuid,0700);
  674. X     (void) chdir(newsuid);
  675. X    }
  676. X
  677. X   (void) sprintf(foo,"../%d/%s",uid,fnsess);
  678. X   (void) rename(foo,fnsess);
  679. X
  680. X   (void) sprintf(foo,"../%d/%s",uid,fnre);
  681. X   (void) rename(foo,fnre); /* in case we're already disconnected */
  682. X
  683. X   uid = newuid;
  684. X   (void) setreuid(uid,euid);
  685. X   setusername();
  686. X
  687. X   if (flagxutmp)
  688. X     if (utmp(glfnsty + PTYUTMP_OFFSET,username,PTYUTMP_SWHOST,date) == -1)
  689. X       ; /* too bad. */
  690. X   if (flagxwtmp)
  691. X     if (wtmp(glfnsty + PTYWTMP_OFFSET,username,PTYWTMP_SWHOST,date) == -1)
  692. X       ; /* too bad. */
  693. X   if (flagsigler)
  694. X     (void) kill(siglerpid,SIGUSR2);
  695. X  }
  696. X}
  697. X
  698. X/*ARGSUSED*/
  699. Xstatic void sig_pipe(i)
  700. Xsig_num i;
  701. X{
  702. X flagsigler = 0; /* XXX: is this appropriate? race? */
  703. X /* Will end up giving child HUP. */
  704. X}
  705. X
  706. X/*ARGSUSED*/
  707. Xstatic void sig_chld(i)
  708. Xsig_num i;
  709. X{
  710. X union wait w;
  711. X
  712. X if (wait3(&w,WNOHANG | WUNTRACED,(struct rusage *) 0) <= 0)
  713. X   return; /* why'd we get the CHLD? it must have stopped & restarted? */
  714. X
  715. X if (w.w_stopval == WSTOPPED)
  716. X  {
  717. X   childsig = w.w_stopsig;
  718. X   flagchild = 2;
  719. X  }
  720. X else
  721. X  {
  722. X   childsig = w.w_termsig; /* can't do much with this */
  723. X   flagchild = 0;
  724. X  }
  725. X}
  726. X
  727. X/*ARGSUSED*/
  728. Xstatic void sig_term(i)
  729. Xsig_num i;
  730. X{
  731. X flagsigler = 0;
  732. X}
  733. X
  734. X/* If we have made it to being master, we should never get TTIN or TTOU, */
  735. X/* except possibly while restarting after a stop (e.g., if the user puts */
  736. X/* us back into the background). But we let the signaller handle putting */
  737. X/* the tty modes back before restarting us, so we should never, ever, */
  738. X/* ever get a TTIN or TTOU. If the user is messing around and we do get */
  739. X/* a TTIN or TTOU, we'll just pretend the child died and hope we get */
  740. X/* around to telling the signaller about it. */
  741. X
  742. X/*ARGSUSED*/
  743. Xstatic void sig_ttin(i)
  744. Xsig_num i;
  745. X{
  746. X if (flagchild)
  747. X  {
  748. X   childsig = SIGTTIN;
  749. X   flagchild = 2;
  750. X  }
  751. X}
  752. X
  753. X/*ARGSUSED*/
  754. Xstatic void sig_ttou(i)
  755. Xsig_num i;
  756. X{
  757. X if (flagchild)
  758. X  {
  759. X   childsig = SIGTTOU;
  760. X   flagchild = 2;
  761. X  }
  762. X}
  763. X
  764. X/*ARGSUSED*/
  765. Xstatic void sig_tstp(i)
  766. Xsig_num i;
  767. X{
  768. X if (flagchild)
  769. X  {
  770. X   childsig = SIGCONT;
  771. X   flagchild = 2;
  772. X  }
  773. X}
  774. X
  775. X/* Most job-control shells (including csh) behave absolutely miserably. */
  776. X/* (Well, that goes without saying.) In particular, rather than sending */
  777. X/* a CONT to every one of their children in the process group, they feel */
  778. X/* a need to kill the entire process group. Grrrr. Because of this, we */
  779. X/* are forced to use the nonintuitive USR1 to communicate CONT, and ignore */
  780. X/* CONT entirely. Anyway, read cont as usr1 where necessary. */
  781. X
  782. X/* We can only get USR1 from the signaller (or from us after reconnect). */
  783. X/* By convention, the signaller handles setting the tty modes back to */
  784. X/* chartty, even though we handled restoring the modes before stop. */
  785. X
  786. X/*ARGSUSED*/
  787. Xstatic void sig_cont(i)
  788. Xsig_num i;
  789. X{
  790. X if (flagchild)
  791. X  {
  792. X   flagchild = 1;
  793. X   (void) kill(slavepid,SIGCONT);
  794. X   (void) kill(pid,SIGWINCH);
  795. X  }
  796. X if (flagconnected == 3)
  797. X   flagconnected = 1; /* XXX: should be internal to master() */
  798. X (void) setpgrp(0,pgrp);
  799. X}
  800. X
  801. X/* If it weren't for WINCH, which must be in the master if NO_FDPASSING, */
  802. X/* and for the stupid conventions surrounding a process's control tty, */
  803. X/* then all mention of fdtty could disappear from master. This would */
  804. X/* slightly complicate the signaller's T{STP,TIN,TOU} handling but make */
  805. X/* reconnect a lot simpler. Sigh. */
  806. X
  807. X/*ARGSUSED*/
  808. Xstatic void sig_winch(i)
  809. Xsig_num i;
  810. X{
  811. X int pg;
  812. X
  813. X flagqwinch = 0;
  814. X#ifdef TTY_WINDOWS
  815. X/* An unfortunate but slight race: Another handler could change the pgrp */
  816. X/* if the child suddenly stops and we're queued for delivery. So we have */
  817. X/* to change it back. */
  818. X pg = getpgrp(0);
  819. X (void) setpgrp(0,pgrp);
  820. X if (!flagsigler)
  821. X   flagqwinch = 1;
  822. X else
  823. X   if (tty_getmodes(fdsty,&tmopty) == 0)
  824. X     if (tty_getmodes(fdtty,&tmowintty) == 0)
  825. X      {
  826. X       tty_copymodes(&tmowinpty,&tmopty);
  827. X       tty_copywin(&tmowinpty,&tmowintty);
  828. X       (void) tty_modifymodes(fdsty,&tmowinpty,&tmopty);
  829. X      }
  830. X (void) setpgrp(0,pg);
  831. X#endif
  832. X}
  833. X
  834. Xstatic int disconnect(fnsty)
  835. Xchar *fnsty;
  836. X{
  837. X if (fdtty != -1)
  838. X  {
  839. X   (void) tty_dissoc(fdtty); /* must succeed */
  840. X   (void) close(fdtty);
  841. X   fdtty = -1;
  842. X  }
  843. X if (fdpass != -1)
  844. X  {
  845. X   /* We used to write the dot to fdpass here. It's in sigler now, to */
  846. X   /* prevent a race condition. */
  847. X   (void) close(fdpass);
  848. X   fdpass = -1;
  849. X  }
  850. X if (fdin != -1)
  851. X  {
  852. X   (void) close(fdin);
  853. X   fdin = -1;
  854. X  }
  855. X if (fdout != -1)
  856. X  {
  857. X   (void) close(fdout);
  858. X   fdout = -1;
  859. X  }
  860. X if (fdre != -1)
  861. X  {
  862. X   (void) close(fdre);
  863. X   fdre = -1;
  864. X  }
  865. X
  866. X fdre = pty_readsock(fnsty,fnre);
  867. X if (fdre == -1)
  868. X   return -1; /* damn. */
  869. X return 0;
  870. X}
  871. X
  872. Xstatic int reconnect()
  873. X{
  874. X int t;
  875. X char buf[1];
  876. X char fntty[TTYNAMELEN]; /* sigh */
  877. X int flags = 0;
  878. X
  879. X t = pty_acceptsock(fdre);
  880. X (void) close(fdre);
  881. X fdre = t;
  882. X if (fdre == -1)
  883. X   return -1;
  884. X
  885. X#define VCF (void) close(fdre)
  886. X#define BONK(xxx,yyy) if ((xxx) == -1) { VCF; return -1; } else (yyy);
  887. X
  888. X/* What about fd 2 for warnings & errors? No, master doesn't use them. */
  889. X
  890. X/* Must have: in, out, siglerpid, pgrp, flagjobctrl. 1, 2, 16, 32, 256. */
  891. X/* Except if NO_FDPASSING: just flagjobctrl in that case. */
  892. X/* If fdtty, must have also tmochartty, tmotty, fntty. 8: 64, 128, 1024. */
  893. X/* Finally, fdpass is independent of all the rest. */
  894. X
  895. X/* CHANGE: With fdpass, fdin and fdout are irrelevant. */
  896. X
  897. X if (pty_sendint(fdre,'p',&pid) == -1)
  898. X  {
  899. X   VCF;
  900. X   return -1;
  901. X  }
  902. X
  903. X while (pty_getch(fdre,buf) == 0)
  904. X   switch(buf[0])
  905. X    {
  906. X#ifdef NO_FDPASSING
  907. X     case 's': BONK(pty_putgetstr(fdre,'s',fntty),flags |= 8) break;
  908. X#else
  909. X     case '0': BONK(pty_putgetfd(fdre,'0',&fdin),flags |= 1) break;
  910. X     case '1': BONK(pty_putgetfd(fdre,'1',&fdout),flags |= 2) break;
  911. X     case 'f': BONK(pty_putgetfd(fdre,'f',&fdpass),flags |= 4) break;
  912. X     case 't': BONK(pty_putgetfd(fdre,'t',&fdtty),flags |= 8) break;
  913. X     case 's': BONK(pty_putgetstr(fdre,'s',fntty),flags |= 1024) break;
  914. X#endif
  915. X     case 'p': BONK(pty_putgetint(fdre,'p',&siglerpid),flags |= 16) break;
  916. X     case 'g': BONK(pty_putgetint(fdre,'g',&pgrp),flags |= 32) break;
  917. X     case 'c': BONK(pty_putgettty(fdre,'c',&tmochartty),flags |= 64) break;
  918. X     case 'n': BONK(pty_putgettty(fdre,'n',&tmotty),flags |= 128) break;
  919. X     case 'j': BONK(pty_putgetint(fdre,'j',&flagjobctrl),flags |= 256) break;
  920. X#ifdef NO_FDPASSING
  921. X     case ' ': if ((flags & 256) != 256) { VCF; return -1; }
  922. X#else
  923. X     case ' ': if (flags & 4) flags |= 3;
  924. X           if ((flags & 307) != 307) { VCF; return -1; }
  925. X           if (flags & 8) if ((flags & 1024) != 1024) { VCF; return -1; }
  926. X#endif
  927. X           if (flags & 8) if ((flags & 192) != 192) { VCF; return -1; }
  928. X
  929. X#ifdef NO_FDPASSING
  930. X               if ((fdtty = open(fntty,O_RDWR)) == -1)
  931. X         return -1;
  932. X           if ((fdin = dup(fdre)) == -1)
  933. X        {
  934. X         (void) close(fdtty);
  935. X         fdtty = -1;
  936. X         return -1;
  937. X        }
  938. X           if ((fdout = dup(fdre)) == -1)
  939. X        {
  940. X         (void) close(fdtty);
  941. X         fdtty = -1;
  942. X         (void) close(fdout);
  943. X         fdout = -1;
  944. X         return -1;
  945. X        }
  946. X#endif
  947. X           VCF; /* yahoo! */
  948. X           (void) close(open(fntty,O_RDWR));
  949. X           /* XXX: do we really have to reattach? */
  950. X           /* I wish there were no concept of controlling tty. */
  951. X           /* Instead, an ioctl on /dev/tty (i.e., fd 3) would */
  952. X           /* return a session identifier. */
  953. X
  954. X           if (fdpass != -1)
  955. X        {
  956. X         if (pty_sendint(fdpass,'G',&siglerpid) == -1)
  957. X           return -1;
  958. X           /* XXX: death(1) might be more intuitive. Then */
  959. X           /* again, it may also be much more destructive. */
  960. X         if (pty_sendfd(fdpass,'m',&fdmty) == -1)
  961. X           return -1;
  962. X         if (pty_sendfd(fdpass,'s',&fdsty) == -1)
  963. X           return -1;
  964. X        }
  965. X
  966. X           /* So that we can disconnect again, we have to reset the */
  967. X           /* siglerpid in fdsess. That done, we've totally severed */
  968. X           /* our previous link to a connection. */
  969. X               (void) lseek(fdsess,(long) sizeof(int),0);
  970. X               (void) write(fdsess,(char *) &siglerpid,sizeof(int));
  971. X
  972. X           flagsigler = 1;
  973. X           (void) setpgrp(0,pgrp);
  974. X           (void) kill(pid,SIGUSR1); /* grrrr */
  975. X           return 0;
  976. X     default: (void) pty_putch(fdre," "); break;
  977. X    }
  978. X VCF;
  979. X return -1;
  980. X}
  981. X
  982. Xstruct timeval instant = { 0, 0 };
  983. X
  984. Xvoid master(fnsty,child)
  985. Xchar *fnsty;
  986. Xint child;
  987. X{
  988. X fd_set rfds;
  989. X fd_set wfds;
  990. X int fdnum;
  991. X int r;
  992. X
  993. X /* XXX: is it a race for child to set pty modes? */
  994. X
  995. X /* Note that we don't close fdsty. */
  996. X
  997. X siglerpid = getppid();
  998. X slavepid = child;
  999. X pid = getpid();
  1000. X glfnsty = fnsty;
  1001. X
  1002. X if (flagsession)
  1003. X  {
  1004. X   /* Security note: This is the only file we actually create, */
  1005. X   /* not counting the reconnect socket. */
  1006. X   (void) sprintf(fnsess,"sess.%s",fnsty + sizeof(DEVSTY) - 3);
  1007. X   fdsess = open(fnsess,O_RDWR | O_CREAT | O_TRUNC,0600);
  1008. X   (void) write(fdsess,(char *) &uid,sizeof(int));
  1009. X   (void) write(fdsess,(char *) &siglerpid,sizeof(int));
  1010. X   (void) write(fdsess,(char *) &pid,sizeof(int));
  1011. X   (void) write(fdsess,(char *) &slavepid,sizeof(int));
  1012. X   /* We'll never actually bother closing fdsess. Who cares? */
  1013. X  }
  1014. X
  1015. X sig_ignore(SIGURG);
  1016. X sig_ignore(SIGIO);
  1017. X sig_ignore(SIGHUP);
  1018. X sig_ignore(SIGQUIT);
  1019. X sig_ignore(SIGINT);
  1020. X sig_sethandler(SIGXCPU,sig_force); sig_handle(SIGXCPU);
  1021. X sig_ignore(SIGXFSZ);
  1022. X sig_ignore(SIGPROF);
  1023. X sig_ignore(SIGVTALRM);
  1024. X
  1025. X sig_default(SIGEMT); /* XXX: really dump? */
  1026. X sig_default(SIGIOT);
  1027. X sig_default(SIGTRAP);
  1028. X sig_default(SIGSYS);
  1029. X sig_default(SIGFPE);
  1030. X sig_default(SIGILL);
  1031. X sig_default(SIGSEGV);
  1032. X
  1033. X sig_default(SIGSTOP);
  1034. X
  1035. X sig_sethandler(SIGTTIN,sig_ttin); sig_handle(SIGTTIN);
  1036. X sig_sethandler(SIGTTOU,sig_ttou); sig_handle(SIGTTOU);
  1037. X sig_sethandler(SIGTSTP,sig_tstp); sig_handle(SIGTSTP);
  1038. X sig_sethandler(SIGUSR1,sig_cont); sig_handle(SIGUSR1);
  1039. X sig_ignore(SIGCONT); /* grrrr. see explanation above sig_cont. */
  1040. X sig_sethandler(SIGPIPE,sig_pipe); sig_handle(SIGPIPE);
  1041. X
  1042. X sig_sethandler(SIGCHLD,sig_chld); sig_handle(SIGCHLD);
  1043. X
  1044. X sig_sethandler(SIGTERM,sig_term); sig_handle(SIGTERM);
  1045. X sig_sethandler(SIGWINCH,sig_winch); sig_handle(SIGWINCH);
  1046. X
  1047. X sig_sethandler(SIGUSR2,sig_usr2); sig_handle(SIGUSR2);
  1048. X
  1049. X if (fdpass != -1)
  1050. X  {
  1051. X   if (pty_sendint(fdpass,'G',&siglerpid) == -1)
  1052. X     death(1);
  1053. X   if (pty_sendfd(fdpass,'m',&fdmty) == -1)
  1054. X     death(1);
  1055. X   if (pty_sendfd(fdpass,'s',&fdsty) == -1)
  1056. X     death(1);
  1057. X  }
  1058. X
  1059. X#define SET_FDNUM fdnum = fdin; if (fdout > fdnum) fdnum = fdout; \
  1060. Xif (fdmty > fdnum) fdnum = fdmty; fdnum++;
  1061. X
  1062. X SET_FDNUM
  1063. X
  1064. X if (fdpass == -1)
  1065. X   (void) fcntl(fdmty,F_SETFL,FNDELAY);
  1066. X   /* If it doesn't work, too bad. */
  1067. X
  1068. X#ifdef SIGINTERRUPT
  1069. X sig_interrupt();
  1070. X#endif
  1071. X
  1072. X for (;;)
  1073. X  {
  1074. X   /* Stage 1: Mangle internal states. This could be made into a */
  1075. X   /* critical section, but there's no point. */
  1076. X
  1077. X   if ((flagconnected == 2) && (flagchild != 2))
  1078. X     flagconnected = 1 + 2 * (flagchild == 0);
  1079. X   if ((flagconnected != 0) && (flagsigler == 0))
  1080. X    {
  1081. X     flagconnected = 0;
  1082. X     if (flagsession)
  1083. X      {
  1084. X       (void) kill(siglerpid,SIGTERM);
  1085. X#ifdef NO_SESSION
  1086. X       ; /* impossible */
  1087. X#else
  1088. X       if (disconnect(fnsty) == -1)
  1089. X     quickdeath(1); /* XXX: sigh */
  1090. X       if (fdnum <= fdre)
  1091. X     fdnum = fdre + 1;
  1092. X#endif
  1093. X      }
  1094. X    }
  1095. X
  1096. X   /* Stage 2: Prepare fds, and select(). */
  1097. X
  1098. X   FD_ZERO(&rfds);
  1099. X   FD_ZERO(&wfds);
  1100. X
  1101. X   if ((fdpass == -1) && (outbuflen < outbufsiz))
  1102. X     FD_SET(fdmty,&rfds);
  1103. X   if ((fdpass == -1) && ptybuflen)
  1104. X     FD_SET(fdmty,&wfds);
  1105. X   if ((fdpass == -1)
  1106. X     &&(ptybuflen < ptybufsiz) && (flagsigler == 1)
  1107. X     &&(flagconnected == 1) && (flagchild == 1))
  1108. X     FD_SET(fdin,&rfds);
  1109. X   if ((fdpass == -1)
  1110. X     &&(outbuflen) && (flagsigler == 1) && (flagconnected == 1))
  1111. X     FD_SET(fdout,&wfds);
  1112. X
  1113. X   if (flagsession && (flagconnected == 0))
  1114. X     FD_SET(fdre,&rfds);
  1115. X
  1116. X   /* The times to flush buffers: when the child has stopped and we're */
  1117. X   /* connected; when the child has died and we're connected; when the */
  1118. X   /* signaller has died and we don't support sessions. */
  1119. X   if (((flagconnected == 1) && (flagchild != 1))
  1120. X     ||((flagconnected == 0) && (flagsession == 0)))
  1121. X     r = select(fdnum,&rfds,&wfds,(fd_set *) 0,&instant);
  1122. X   else
  1123. X     r = select(fdnum,&rfds,&wfds,(fd_set *) 0,(struct timeval *) 0);
  1124. X
  1125. X
  1126. X   /* Stage 3: Interpret the results and handle special cases. */
  1127. X
  1128. X   if (r <= 0)
  1129. X     if (r == -1)
  1130. X       switch(errno)
  1131. X        {
  1132. X         case EBADF: death(1);
  1133. X                     break;
  1134. X         case EINTR: break; /* fine. */
  1135. X         case EINVAL: break; /* impossible. */
  1136. X         default: break; /* say what? */
  1137. X        }
  1138. X     else /* r is 0 */
  1139. X      {
  1140. X       if (flagconnected == 1) /* flagchild is 0 or 2 */
  1141. X     if (flagchild == 0)
  1142. X       break; /* That's it! Child died, and we're outta here! */
  1143. X     else
  1144. X      { /* done with flush, time to stop sigler & idle */
  1145. X       if (flagjobctrl)
  1146. X        {
  1147. X         /* As usual, if we don't have a tty, tmotty == tmochartty
  1148. X        and it won't matter that fdtty is undefined. */
  1149. X         (void) setpgrp(0,pgrp);
  1150. X           if (tty_modifymodes(fdtty,&tmotty,&tmochartty) == -1)
  1151. X           ; /* XXX: what to do? */
  1152. X         (void) setpgrp(0,pid);
  1153. X         switch(childsig)
  1154. X          {
  1155. X           case SIGSTOP: (void) kill(siglerpid,SIGSTOP); break;
  1156. X           case SIGTTOU: (void) kill(siglerpid,SIGTTOU); break;
  1157. X           case SIGTTIN: (void) kill(siglerpid,SIGTTIN); break;
  1158. X           case SIGTSTP: (void) kill(siglerpid,SIGTSTP); break;
  1159. X           case SIGCONT: break; /* special case---see sig_tstp */
  1160. X           default: (void) kill(siglerpid,SIGSTOP); break;
  1161. X          }
  1162. X         flagconnected = 2;
  1163. X        }
  1164. X      }
  1165. X       else if (flagconnected == 0) /* non-session, sigler dead */
  1166. X     break; /* Giving pty pgrp a HUP, ho hum */
  1167. X     /* Most pgrp-based killing would be more logically done */
  1168. X     /* one process at a time, i.e., we should give our child */
  1169. X     /* a signal specially. But nobody else does, so we won't. */
  1170. X      }
  1171. X   else
  1172. X    {
  1173. X#ifndef NO_SESSION
  1174. X     if (flagconnected == 0)
  1175. X       if (FD_ISSET(fdre,&rfds))
  1176. X     if (reconnect() == -1)
  1177. X      {
  1178. X       if (disconnect(fnsty) == -1)
  1179. X         quickdeath(1); /* sigh */
  1180. X           if (fdnum <= fdre)
  1181. X         fdnum = fdre + 1;
  1182. X          }
  1183. X     else
  1184. X      {
  1185. X       flagconnected = 1; /* yay! */
  1186. X       SET_FDNUM
  1187. X       continue; /* XXX */
  1188. X      }
  1189. X#endif
  1190. X
  1191. X
  1192. X   /* Stage 4: Do normal I/O. */
  1193. X
  1194. X#ifdef SIGINTERRUPT
  1195. X     sig_startring(); /* blocking? never heard of it */
  1196. X#endif
  1197. X
  1198. X     if (FD_ISSET(fdin,&rfds))
  1199. X      {
  1200. X       /* ptybuflen must be smaller than ptybufsiz. */
  1201. X       r = read(fdin,ptybuf + ptybuflen,ptybufsiz - ptybuflen);
  1202. X       if (r == -1)
  1203. X     switch(errno)
  1204. X      {
  1205. X       case EINTR: case EWOULDBLOCK: break; /* fine */
  1206. X       default: death(1);
  1207. X      }
  1208. X       else if (r == 0) /* EOF */
  1209. X    {
  1210. X     ; /* XXX: there's no way to pass an EOF */
  1211. X    }
  1212. X       else
  1213. X     ptybuflen += r;
  1214. X      }
  1215. X     if (FD_ISSET(fdmty,&rfds))
  1216. X      {
  1217. X       /* outbuflen must be smaller than outbufsiz. */
  1218. X       r = read(fdmty,outbuf + outbuflen,outbufsiz - outbuflen);
  1219. X       if (r == -1)
  1220. X     switch(errno)
  1221. X      {
  1222. X       case EINTR: case EWOULDBLOCK: break; /* fine */
  1223. X       default: death(1);
  1224. X      }
  1225. X       else if (r == 0) /* EOF */
  1226. X    {
  1227. X     ; /* This can't happen. The slave can't pass an EOF. */
  1228. X     /* XXX: Should we close fdout anyway? */
  1229. X    }
  1230. X       else
  1231. X     outbuflen += r;
  1232. X      }
  1233. X     if (FD_ISSET(fdout,&wfds))
  1234. X      {
  1235. X       r = write(fdout,outbuf,outbuflen);
  1236. X       if (r == -1)
  1237. X     switch(errno)
  1238. X      {
  1239. X       case EINTR: case EWOULDBLOCK: break; /* fine */
  1240. X       default: death(1);
  1241. X      }
  1242. X       else if (r == 0) /* ? */
  1243. X     ; /* impossible */
  1244. X       else if (r == outbuflen)
  1245. X     outbuflen = 0;
  1246. X       else
  1247. X    {
  1248. X     outbuflen -= r;
  1249. X         copy(outbuf,outbuf + r,outbuflen);
  1250. X    }
  1251. X      }
  1252. X     if (FD_ISSET(fdmty,&wfds))
  1253. X      {
  1254. X       r = write(fdmty,ptybuf,ptybuflen);
  1255. X       if (r == -1)
  1256. X     switch(errno)
  1257. X      {
  1258. X       case EINTR: case EWOULDBLOCK: break; /* fine */
  1259. X       default: death(1);
  1260. X      }
  1261. X       else if (r == 0) /* ? */
  1262. X     ; /* impossible */
  1263. X       else if (r == ptybuflen)
  1264. X     ptybuflen = 0;
  1265. X       else
  1266. X    {
  1267. X     ptybuflen -= r;
  1268. X         copy(ptybuf,ptybuf + r,ptybuflen);
  1269. X    }
  1270. X      }
  1271. X
  1272. X#ifdef SIGINTERRUPT
  1273. X     sig_stopring();
  1274. X#endif
  1275. X    }
  1276. X  }
  1277. X
  1278. X death(0);
  1279. X}
  1280. END_OF_FILE
  1281.   if test 18086 -ne `wc -c <'master.c'`; then
  1282.     echo shar: \"'master.c'\" unpacked with wrong size!
  1283.   fi
  1284.   # end of 'master.c'
  1285. fi
  1286. if test -f 'pty.c' -a "${1}" != "-c" ; then 
  1287.   echo shar: Will not clobber existing file \"'pty.c'\"
  1288. else
  1289.   echo shar: Extracting \"'pty.c'\" \(10563 characters\)
  1290.   sed "s/^X//" >'pty.c' <<'END_OF_FILE'
  1291. X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */
  1292. X
  1293. X/*
  1294. Xpty.c: run a program under a pty session
  1295. X*/
  1296. X
  1297. X#include <stdio.h>
  1298. Xextern unsigned short getuid(); /* grrrr */
  1299. Xextern unsigned short geteuid(); /* grrrr */
  1300. X#include "config.h"
  1301. X#include "getopt.h"
  1302. X#include "err.h"
  1303. X#include "pty.h"
  1304. X#include "tty.h"
  1305. X#include "texts.h"
  1306. X#include "sig.h"
  1307. X#include "sigler.h"
  1308. X#include "master.h"
  1309. X#include "slave.h"
  1310. X#include "file.h"
  1311. X#include "logs.h"
  1312. X#include "misc.h"
  1313. X
  1314. Xint flagpcbreak = 0; /* -pc, character-at-a-time */
  1315. Xint flagpnew = 1; /* -pd, new line discipline---traditionally off to start */
  1316. Xint flagpecho = 1; /* -pe, echo characters */
  1317. Xint flagpcrmod = 1; /* -pn, munge carriage returns */
  1318. Xint flagpraw = 0; /* -pr, raw mode */
  1319. Xint flagpcrt = 1; /* -ps, screen */
  1320. X
  1321. Xgetfreepty(fnmty,fnsty,pty1,pty2)
  1322. Xregister char fnmty[sizeof(DEVMTY)];
  1323. Xregister char fnsty[sizeof(DEVSTY)];
  1324. Xregister char pty1[sizeof(PTY1)];
  1325. Xregister char pty2[sizeof(PTY2)];
  1326. X{
  1327. X register char *c1;
  1328. X register char *c2;
  1329. X register char *c1start; /* for ``random'' pty searching */
  1330. X register char *c2start;
  1331. X int e;
  1332. X
  1333. X if (flagxrandom)
  1334. X  {
  1335. X   c1start = pty1 + (pid % (sizeof(PTY1) - 1));
  1336. X   c2start = pty2 + ((pid + date) % (sizeof(PTY2) - 1));
  1337. X  }
  1338. X else
  1339. X  {
  1340. X   c1start = pty1;
  1341. X   c2start = pty2;
  1342. X  }
  1343. X
  1344. X c1 = c1start;
  1345. X do
  1346. X  {
  1347. X   fnmty[sizeof(DEVMTY) - 3] = *c1;
  1348. X   fnmty[sizeof(DEVMTY) - 2] = pty2[0];
  1349. X   if (!access(fnmty,F_OK))
  1350. X    {
  1351. X     c2 = c2start;
  1352. X     fnsty[sizeof(DEVSTY) - 3] = *c1;
  1353. X     fnmty[sizeof(DEVMTY) - 2] = fnsty[sizeof(DEVSTY) - 2] = *c2;
  1354. X     do
  1355. X      {
  1356. X#ifdef DESPERATE_ALARMS
  1357. X       sig_startring();
  1358. X#endif
  1359. X
  1360. X/* Some other process could come along and mess up our test by opening */
  1361. X/* the master side before we do. But in that case they'll get the pty */
  1362. X/* anyway, and we'll move on to another possibility without comment. */
  1363. X       if (flagxchkopen)
  1364. X    {
  1365. X#ifdef DONT_NDELAY
  1366. X         fdsty = open(fnsty,O_RDWR);
  1367. X#else
  1368. X         fdsty = open(fnsty,O_RDWR | O_NDELAY);
  1369. X#endif
  1370. X         e = errno;
  1371. X         fdmty = open(fnmty,O_RDWR);
  1372. X    }
  1373. X       else
  1374. X    {
  1375. X         fdmty = open(fnmty,O_RDWR);
  1376. X         fdsty = open(fnsty,O_RDWR);
  1377. X     e = errno;
  1378. X    }
  1379. X
  1380. X#ifdef DESPERATE_ALARMS
  1381. X       sig_stopring();
  1382. X#endif
  1383. X
  1384. X       if (fdmty != -1)
  1385. X    {
  1386. X     if (flagxskipopen && (fdsty != -1))
  1387. X       warnerr2("pty: warning: slave %s still in use\n",fnsty);
  1388. X     else
  1389. X      {
  1390. X       if ((fdsty == -1) && (e != EINTR) && (e != EWOULDBLOCK))
  1391. X         fatalerr2p(6,"pty: fatal: slave %s unopenable",fnsty,e);
  1392. X       if (flagxchkopen)
  1393. X         if (fdsty == -1)
  1394. X          {
  1395. X           fdsty = open(fnsty,O_RDWR);
  1396. X           e = errno;
  1397. X          }
  1398. X         else
  1399. X           warnerr2("pty: warning: slave %s still in use\n",fnsty);
  1400. X       if (fdsty == -1)
  1401. X         fatalerr2p(6,"pty: fatal: slave %s unopenable",fnsty,e);
  1402. X       else
  1403. X        {
  1404. X         if (flagxchkopen)
  1405. X           if (fcntl(fdsty,F_SETFL,0) == -1)
  1406. X         fatalerrp(6,"pty: fatal: can't fcntl pty",e);
  1407. X         return 0;
  1408. X        }
  1409. X      }
  1410. X    }
  1411. X
  1412. X       if (fdmty != -1) (void) close(fdmty);
  1413. X       if (fdsty != -1) (void) close(fdsty);
  1414. X       if (!(*(++c2)))
  1415. X     c2 = pty2;
  1416. X       fnmty[sizeof(DEVMTY) - 2] = fnsty[sizeof(DEVSTY) - 2] = *c2;
  1417. X      }
  1418. X     while (c2 != c2start);
  1419. X    }
  1420. X   if (!(*(++c1)))
  1421. X     c1 = pty1;
  1422. X  }
  1423. X while (c1 != c1start);
  1424. X return -1;
  1425. X}
  1426. X
  1427. Xchar fnmty[sizeof(DEVMTY)] = DEVMTY;
  1428. Xchar fnsty[sizeof(DEVSTY)] = DEVSTY;
  1429. Xchar pty1[sizeof(PTY1)] = PTY1;
  1430. Xchar pty2[sizeof(PTY2)] = PTY2;
  1431. X
  1432. Xmain(argc,argv)
  1433. Xint argc;
  1434. Xchar *argv[];
  1435. X{
  1436. X int opt;
  1437. X int f;
  1438. X
  1439. X uid = getuid();
  1440. X euid = geteuid();
  1441. X pid = getpid();
  1442. X pgrp = getpgrp(0);
  1443. X date = now();
  1444. X setusername();
  1445. X
  1446. X while ((opt = getopt(argc,argv,"qQvdDe3Ef:FjJsStTp:x:0ACHUVW")) != EOF)
  1447. X   switch(opt)
  1448. X    {
  1449. X     case 'A': fatalinfo(1,ptyauthor);
  1450. X     case 'C': fatalinfo(1,ptycopyright);
  1451. X     case 'H': fatalinfo(1,ptyhelp);
  1452. X     case 'U': fatalinfo(1,ptyusage);
  1453. X     case 'V': fatalinfo(1,ptyversion);
  1454. X     case 'W': fatalinfo(1,ptywarranty);
  1455. X     case '?': fatalinfo(1,ptyusage);
  1456. X     case 'q': flagquiet = 1; break;
  1457. X     case 'Q': flagquiet = 0; flagverbose = 0; break;
  1458. X     case 'v': flagverbose = 1; break;
  1459. X     case 'd': flagdetached = 1; flagjobctrl = 0; flagttymodes = 0; break;
  1460. X     case 'D': flagdetached = 0; flagjobctrl = 1; flagttymodes = 1; break;
  1461. X     case 'e': flagsameerr = 2; break;
  1462. X     case '3': flagsameerr = 1; break;
  1463. X     case 'E': flagsameerr = 0; break;
  1464. X     case 'f': flagfdpass = 1; 
  1465. X           if (sscanf(optarg,"%d",&fdpass) < 1) fatalinfo(1,ptyusage);
  1466. X           break;
  1467. X     case 'F': flagfdpass = 0; break;
  1468. X     case 'j': flagjobctrl = 1; break;
  1469. X     case 'J': flagjobctrl = 0; break;
  1470. X     case 's': flagsession = 1; flagxutmp = 1; break;
  1471. X     case 'S': flagsession = 0; flagxutmp = 0; break;
  1472. X     case 't': flagttymodes = 1; break;
  1473. X     case 'T': flagttymodes = 0; break;
  1474. X     case '0': flagsameerr = 2; flagsession = 0; flagttymodes = 0;
  1475. X           flagxutmp = 0; /* XXX: also flagxwtmp = 0? */
  1476. X           flagpcbreak = 3; flagpraw = 3; flagpecho = 2; flagpnew = 2;
  1477. X           break;
  1478. X     case 'p': while (opt = *(optarg++))
  1479. X         switch(opt)
  1480. X          {
  1481. X           case 'c': flagpcbreak = 3; break;
  1482. X           case 'C': flagpcbreak = 2; break;
  1483. X           case 'd': flagpnew = 3; break;
  1484. X           case 'D': flagpnew = 2; break;
  1485. X           case 'e': flagpecho = 3; break;
  1486. X           case 'E': flagpecho = 2; break;
  1487. X           case 'n': flagpcrmod = 3; break;
  1488. X           case 'N': flagpcrmod = 2; break;
  1489. X           case 'r': flagpraw = 3; break;
  1490. X           case 'R': flagpraw = 2; break;
  1491. X           case 's': flagpcrt = 3; break;
  1492. X           case 'S': flagpcrt = 2; break;
  1493. X           case '0': flagpcbreak = 3; flagpraw = 3;
  1494. X                 flagpecho = 2; flagpnew = 2;
  1495. X                 break;
  1496. X           default: fatalinfo(1,ptyusage); break;
  1497. X          }
  1498. X               break;
  1499. X     case 'x': while (opt = *(optarg++))
  1500. X         switch(opt)
  1501. X          {
  1502. X           case 'c': flagxchown = 1; break;
  1503. X           case 'C': flagxchown = 0; break;
  1504. X           case 'u': flagxutmp = 1; break;
  1505. X           case 'U': flagxutmp = 0; break;
  1506. X           case 'w': flagxwtmp = 1; break;
  1507. X           case 'W': flagxwtmp = 0; break;
  1508. X           case 'x': flagxexcl = 1; break;
  1509. X           case 'X': flagxexcl = 0; break;
  1510. X           case 'e': flagxerrwo = 1; break;
  1511. X           case 'E': flagxerrwo = 0; break;
  1512. X           case 'n': flagxchkopen = 1; break;
  1513. X           case 'N': flagxchkopen = 0; break;
  1514. X           case 'o': flagxskipopen = 1; break;
  1515. X           case 'O': flagxskipopen = 0; break;
  1516. X           case 'r': flagxrandom = 1; break;
  1517. X           case 'R': flagxrandom = 0; break;
  1518. X           case 's': flagxsetuid = 1; break;
  1519. X           case 'S': flagxsetuid = 0; break;
  1520. X           default: fatalinfo(1,ptyusage); break;
  1521. X          }
  1522. X               break;
  1523. X    }
  1524. X argv += optind, argc -= optind;
  1525. X
  1526. X if (!*argv)
  1527. X   fatalinfo(1,ptyusage);
  1528. X
  1529. X /* Option forcing. */
  1530. X#ifdef NO_UTMP
  1531. X  if (flagxutmp) if (flagverbose) warnerr2("%s","pty: utmp forced off\n");
  1532. X  flagxutmp = 0;
  1533. X#endif
  1534. X#ifdef NO_WTMP
  1535. X  if (flagxwtmp) if (flagverbose) warnerr2("%s","pty: wtmp forced off\n");
  1536. X  flagxwtmp = 0;
  1537. X#endif
  1538. X#ifdef NO_CHOWN
  1539. X  if (flagxchown) if (flagverbose) warnerr2("%s","pty: chown forced off\n");
  1540. X  flagxchown = 0;
  1541. X#endif
  1542. X#ifdef NO_SESSION
  1543. X  if (flagsession) if (flagverbose) warnerr2("%s","pty: session forced off\n");
  1544. X  flagsession = 0;
  1545. X#endif
  1546. X#ifdef MUST_UTMP
  1547. X  if (flagxutmp) if (flagverbose) warnerr2("%s","pty: utmp forced on\n");
  1548. X  flagxutmp = 1;
  1549. X#endif
  1550. X#ifdef MUST_WTMP
  1551. X  if (flagxwtmp) if (flagverbose) warnerr2("%s","pty: wtmp forced on\n");
  1552. X  flagxwtmp = 1;
  1553. X#endif
  1554. X#ifdef MUST_CHOWN
  1555. X  if (flagxchown) if (flagverbose) warnerr2("%s","pty: chown forced on\n");
  1556. X  flagxchown = 1;
  1557. X#endif
  1558. X#ifdef MUST_SESSION
  1559. X  if (flagsession) if (flagverbose) warnerr2("%s","pty: session forced on\n");
  1560. X  flagsession = 1;
  1561. X#endif
  1562. X#ifdef NO_FDPASSING
  1563. X  if (flagfdpass) if (flagverbose) warnerr2("%s","pty: fd passing forced off\n");
  1564. X  flagfdpass = 0;
  1565. X#endif
  1566. X
  1567. X /* Option munging. */
  1568. X if (flagsession) flagsameerr = 0;
  1569. X if (flagdetached) flagttymodes = 0;
  1570. X if (flagxskipopen) flagxchkopen = 1;
  1571. X
  1572. X if (!flagxsetuid)
  1573. X  {
  1574. X   (void) setreuid(uid,uid);
  1575. X   euid = uid;
  1576. X  }
  1577. X
  1578. X
  1579. X sig_init();
  1580. X sig_sethandler(SIGALRM,nothing); sig_handle(SIGALRM);
  1581. X sig_default(SIGTTIN);
  1582. X sig_default(SIGTTOU);
  1583. X
  1584. X if (fdpass == -1) /* wow, was this a source of bugs. */
  1585. X  {
  1586. X   fdin = 0;
  1587. X   fdout = 1;
  1588. X  }
  1589. X
  1590. X if (flagdetached)
  1591. X  {
  1592. X   tty_initmodes(&tmopty,flagpcbreak,flagpnew,flagpecho,
  1593. X             flagpcrmod,flagpraw,flagpcrt);
  1594. X  }
  1595. X else
  1596. X  {
  1597. X   if ((fdtty = tty_getctrl()) == -1)
  1598. X     fatalerr(2,"pty: fatal: cannot find control terminal; try -d?\n");
  1599. X   if (tty_getmodes(fdtty,&tmotty) == -1)
  1600. X     fatalerr(3,"pty: fatal: cannot get current tty modes\n");
  1601. X     /* XXX: is there a way to recover more gracefully? */
  1602. X   tty_copymodes(&tmopty,&tmotty);
  1603. X   tty_mungemodes(&tmopty,flagpcbreak,flagpnew,flagpecho,
  1604. X              flagpcrmod,flagpraw,flagpcrt);
  1605. X   tty_copymodes(&tmochartty,&tmotty);
  1606. X   if (flagttymodes)
  1607. X     tty_charmode(&tmochartty);
  1608. X  }
  1609. X
  1610. X /* XXX: Here would be a good spot to include pty limits, say through */
  1611. X /* the file PTYDIR/LIMITS. Lines of the form user group num, saying */
  1612. X /* that user in that group is limited to num ptys, with * for all. */
  1613. X /* All pty use would have to be logged somewhere. Anyway, with a */
  1614. X /* streams-based pty, there wouldn't be much point to limits. */
  1615. X
  1616. X if (getfreepty(fnmty,fnsty,pty1,pty2) == -1)
  1617. X   fatalerr(5,"pty: fatal: no ptys available\n");
  1618. X
  1619. X if (flagverbose)
  1620. X   warnerr2("pty: successfully opened pty %s\n",fnsty);
  1621. X
  1622. X if (tty_modifymodes(fdtty,&tmochartty,&tmotty) == -1)
  1623. X  {
  1624. X   (void) tty_setmodes(fdtty,&tmotty); /* XXX --- gasp */
  1625. X   fatalerr(4,"pty: fatal: cannot set modes of original tty\n");
  1626. X  }
  1627. X
  1628. X/* In general, BSD systems check MAXUPRC against the effective uid, */
  1629. X/* rather than the real uid; and they check it during a fork(). */
  1630. X/* The combination of these annoying behaviors means that we have */
  1631. X/* to switch uids while forking, hence possibly losing any security */
  1632. X/* measures we may have set up before the fork(). Grrrr. */
  1633. X
  1634. X (void) setreuid(euid,uid);
  1635. X if ((f = fork()) == -1)
  1636. X  {
  1637. X   (void) tty_modifymodes(fdtty,&tmotty,&tmochartty);
  1638. X   fatalerr(7,"pty: fatal: cannot fork once\n");
  1639. X   /* After this, the signaller will handle tty modes. */
  1640. X  }
  1641. X else if (f == 0)
  1642. X   if ((f = fork()) == -1)
  1643. X    {
  1644. X     (void) kill(pid,SIGTERM); /*XXX*/
  1645. X     fatalerr(7,"pty: fatal: cannot fork twice\n");
  1646. X    }
  1647. X   else if (f == 0)
  1648. X    {
  1649. X     (void) setreuid(uid,euid);
  1650. X     slave(fnsty,argv);
  1651. X    }
  1652. X   else
  1653. X    {
  1654. X     (void) setreuid(uid,euid);
  1655. X     if (flagsession)
  1656. X       if (sessdir() == -1)
  1657. X         fatal(1);
  1658. X     master(fnsty,f);
  1659. X    }
  1660. X else
  1661. X  {
  1662. X   (void) setreuid(uid,euid);
  1663. X   if (flagsession)
  1664. X     if (sessdir() == -1)
  1665. X      {
  1666. X       fatalerr(8,"pty: fatal: cannot change to session directory\n");
  1667. X       (void) tty_modifymodes(fdtty,&tmotty,&tmochartty);
  1668. X      }
  1669. X   sigler(fnsty,f);
  1670. X  }
  1671. X
  1672. X fatal(9); /* just in case */
  1673. X /*NOTREACHED*/
  1674. X}
  1675. END_OF_FILE
  1676.   if test 10563 -ne `wc -c <'pty.c'`; then
  1677.     echo shar: \"'pty.c'\" unpacked with wrong size!
  1678.   fi
  1679.   # end of 'pty.c'
  1680. fi
  1681. echo shar: End of archive 2 \(of 6\).
  1682. cp /dev/null ark2isdone
  1683. MISSING=""
  1684. for I in 1 2 3 4 5 6 ; do
  1685.     if test ! -f ark${I}isdone ; then
  1686.     MISSING="${MISSING} ${I}"
  1687.     fi
  1688. done
  1689. if test "${MISSING}" = "" ; then
  1690.     echo You have unpacked all 6 archives.
  1691.     rm -f ark[1-9]isdone
  1692. else
  1693.     echo You still must unpack the following archives:
  1694.     echo "        " ${MISSING}
  1695. fi
  1696. exit 0
  1697. exit 0 # Just in case...
  1698. -- 
  1699. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  1700. Use a domain-based address or give alternate paths, or you may lose out.
  1701.